package com.ls.service.impl;

import cn.hutool.poi.excel.ExcelReader;
import cn.hutool.poi.excel.ExcelUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ls.controller.logistic.model.AddLogisticModel;
import com.ls.controller.logistic.model.QueryLogisticModel;
import com.ls.controller.logistic.model.LogisticsSmsModel;
import com.ls.entity.*;
import com.ls.enums.SignEnum;
import com.ls.mapper.LogisticMapper;
import com.ls.service.IIsSendService;
import com.ls.service.ILogisticService;
import com.ls.utils.FileUtils;
import com.ls.utils.ResultData;
import com.ls.utils.rsa.Base64Utils;
import com.ls.utils.sms.SendSmsModel;
import com.ls.utils.sms.SmsPyUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

import static com.ls.constant.SystemConstants.*;

/**
 * <p>
 * 物流
 * </p>
 *
 * @author pengyu
 * @since 2024-10-12
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class LogisticServiceImpl extends ServiceImpl<LogisticMapper, Logistic> implements ILogisticService {
    // 中通API配置
    @Value("${ZTO.url}")
    private String url;
    @Value("${ZTO.appKey}")
    private String appKey;
    @Value("${ZTO.appSecret}")
    private String appSecret;
    private final IIsSendService isSendService;
    /**
     * 分页物流记录
     */
    @Override
    public ResultData pageList(QueryLogisticModel model) {
        Integer sendSmsStatus = null;
        Integer receiveSmsStatus = null;
        if (model.getSendStatus()!=null){
            List<Integer> sendStatus = Arrays.stream(model.getSendStatus().split(","))
                    .map(Integer::parseInt)
                    .collect(Collectors.toList());
            log.info("发送状态：{}",sendStatus);
            //是否搜索发件短信
            if (sendStatus.size()==1){
                Integer status=sendStatus.get(0);
                if (status.equals(NUMBER_1)){
                    sendSmsStatus = SMS_STATUS_TRUE;
                }else if (status.equals(NUMBER_2)){
                    receiveSmsStatus = SMS_STATUS_TRUE;
                }
            }
            //是否搜索签收短信
            if (sendStatus.size()==2){
                Integer status=sendStatus.get(1);
                if (status.equals(NUMBER_1)){
                    sendSmsStatus = SMS_STATUS_TRUE;
                }else if (status.equals(NUMBER_2)){
                    receiveSmsStatus = SMS_STATUS_TRUE;
                }
            }
        }
        LambdaQueryWrapper<Logistic> wrapper = new LambdaQueryWrapper<Logistic>()
                .eq(model.getLogisticType()!=null, Logistic::getLogisticType, model.getLogisticType())
                .eq(model.getLogisticName()!=null, Logistic::getLogisticName, model.getLogisticName())
                .like(StringUtils.isNotBlank(model.getLogisticNum()), Logistic::getLogisticNum, model.getLogisticNum())
                .eq(StringUtils.isNotBlank(model.getLogisticStatus()), Logistic::getLogisticStatus, model.getLogisticStatus())
                .eq(sendSmsStatus!=null, Logistic::getSendSmsStatus, sendSmsStatus)
                .eq(receiveSmsStatus!=null, Logistic::getReceiveSmsStatus, receiveSmsStatus)
                .like(model.getProductName()!=null, Logistic::getProductName, model.getProductName())
                .like(StringUtils.isNotBlank(model.getNickname()), Logistic::getNickname, model.getNickname())
                .like(StringUtils.isNotBlank(model.getPhone()), Logistic::getPhone, model.getPhone())
                .like(StringUtils.isNotBlank(model.getProvince()), Logistic::getProvince, model.getProvince())
                .like(StringUtils.isNotBlank(model.getCity()), Logistic::getCity, model.getCity())
                .between(StringUtils.isNotBlank(model.getBeginSt())&&StringUtils.isNotBlank(model.getEndSt()), Logistic::getCreateTime, model.getBeginSt(), model.getEndSt())
                .orderByDesc(Logistic::getCreateTime);
        Page page = new Page(model.getPageNum(), model.getPageSize());
        IPage<Logistic> dtoIPage = this.baseMapper.selectPage(page, wrapper);
        return ResultData.successData(dtoIPage);
    }
    /**导入物流单号*/
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResultData analyseExcelLogistic(File file,Integer type) {
        try (ExcelReader reader = ExcelUtil.getReader(file)) {
            List<Logistic> records = new ArrayList<>();
            StringBuilder error = new StringBuilder();
            List<String> columnNames = new ArrayList<>(reader.getHeaderAlias().keySet());
            log.info("Excel列名：{}", columnNames);
            if (columnNames.isEmpty()) {
                //读取第一行
                List<Object> firstRow = reader.readRow(0);
                if (firstRow != null && !firstRow.isEmpty()) {
                    columnNames = firstRow.stream()
                            .map(Object::toString)
                            .collect(Collectors.toList());
                    log.info("强制使用第一行作为列名：{}", columnNames);

                    // 设置新的起始行（跳过标题行）
                    reader.setSheet(0);
                    reader.read(1, Integer.MAX_VALUE);
                } else {
                    String msg = "Excel文件没有列名且第一行为空";
                    log.error(msg);
                    throw new RuntimeException(msg);
                }
            }

            // 2. 建立列名与Linkman属性的映射关系
            Map<String, String> columnMapping = buildColumnMapping(columnNames);
            log.info("列名与属性的映射关系：{}", columnMapping);
            List<Map<String, Object>> readAll = reader.readAll();
            // 新增：预加载所有已存在运单号（批量查询优化性能）
            Set<String> existLogisticNums = this.list(new LambdaQueryWrapper<Logistic>()
                            .select(Logistic::getLogisticNum))
                    .stream()
                    .map(Logistic::getLogisticNum)
                    .collect(Collectors.toSet());

            // 新增：跟踪当前批次的运单号
            Set<String> batchNums = new HashSet<>();
            log.info("数据：{}",readAll.size());
            for (Map<String, Object> row : readAll) {
                try {
                    Logistic logistic = new Logistic();
                    // 4. 动态设置属性
                    for (Map.Entry<String, String> entry : columnMapping.entrySet()) {
                        String excelColumn = entry.getKey();
                        String propertyName = entry.getValue();
                        Field field = Logistic.class.getDeclaredField(propertyName);
                        field.setAccessible(true);
                        if (row.containsKey(excelColumn) && row.get(excelColumn) != null) {
                            Object value = row.get(excelColumn);
                            log.info("列名：{}，属性名：{}，属性值：{}", excelColumn, propertyName, value);
                            field.set(logistic, value.toString());
                            log.info("当前物流：{}", logistic);
                        }
                    }
                    log.info("当前物流：{}", logistic);
                    // 验证必要字段
                    if (StringUtils.isBlank(logistic.getLogisticNum())) {
                        continue;
                    }

                    String logisticNum = logistic.getLogisticNum();
                    // 静默过滤重复号码
                    if (existLogisticNums.contains(logisticNum) || batchNums.contains(logisticNum)) {
                        continue;
                    }
                    logistic.setLogisticStatus("");
                    logistic.setCustomerId((long) NUMBER_0);
                    if (type!=1){
                        logistic.setSendSmsStatus(SMS_STATUS_SENDING);
                    }else {
                        logistic.setSendSmsStatus(NUMBER_0);
                    }
                    logistic.setReceiveSmsStatus(NUMBER_0);
                    logistic.setCreateTime(LocalDateTime.now());
                    batchNums.add(logisticNum);
                    records.add(logistic);
                }catch (Exception e){
                    error.append("第").append(readAll.indexOf(row) + 1)
                            .append("行数据错误: ").append(e.getMessage()).append("; ");
                }
            }
            this.saveBatch(records);
            records.forEach(logistic ->
            {
                log.info("保存的物流：{}", logistic);
                if (type!=1){
                    log.info("发送短信:{}",logistic.getLogisticId());
                    IsSend isSend=isSendService.getOne(new LambdaQueryWrapper<IsSend>().eq(IsSend::getProvince,logistic.getProvince()));
                    if (logistic.getLogisticType().equals("碰碰推")&&isSend.getSendPpt().equals(NUMBER_1)||logistic.getLogisticType().equals("乐信通")&&isSend.getSendLxt().equals(NUMBER_1)){
                       log.info("发送短信");
                        LogisticsSmsModel model = LogisticsSmsModel.builder()
                                .logisticId(logistic.getLogisticId())
                                .outerPhone(logistic.getPhone())
                                .outerName(logistic.getNickname())
                                .content(SEND_SMS_CONTENT)
                                .sendStatus(NUMBER_1)
                                .build();
                        send(model,1);
                    }
                }
            });
            return ResultData.successMsg("成功导入" + records.size() + "条数据");
        } catch (Exception e) {
            log.error("物流数据解析异常", e);
            return ResultData.failure("文件解析失败：" + e.getMessage());
        }
    }
    /**
     * 建立列名与Linkman属性的映射关系
     */
    private Map<String, String> buildColumnMapping(List<String> columnNames) {
        // 预定义的列名映射（支持多种可能的列名）
        Map<String, String> predefinedMappings = new HashMap<>();

        predefinedMappings.put("发件人", "logisticType");
        predefinedMappings.put("发件人姓名", "logisticType");
        predefinedMappings.put("发件物流", "logisticName");
        predefinedMappings.put("快递公司", "logisticName");
        predefinedMappings.put("运单编号", "logisticNum");
        predefinedMappings.put("运单号", "logisticNum");
        predefinedMappings.put("物品信息", "productName");
        predefinedMappings.put("商品名称", "productName");
        predefinedMappings.put("收件人", "nickname");
        predefinedMappings.put("收件人信息", "nickname");
        predefinedMappings.put("收件人手机号", "phone");
        predefinedMappings.put("收件人手机/电话", "phone");
        predefinedMappings.put("收件省", "province");
        predefinedMappings.put("收件人省", "province");
        predefinedMappings.put("收件市", "city");
        predefinedMappings.put("收件人市", "city");
        predefinedMappings.put("收件区", "district");
        predefinedMappings.put("收件人区", "district");
        predefinedMappings.put("收件地址", "address");
        predefinedMappings.put("收件人详细地址", "address");

        // 创建最终映射关系
        Map<String, String> columnMapping = new HashMap<>();

        for (String column : columnNames) {
            // 去除可能的空格
            String cleanColumn = column.trim();

            // 查找匹配的预定义映射
            for (Map.Entry<String, String> entry : predefinedMappings.entrySet()) {
                if (entry.getKey().equalsIgnoreCase(cleanColumn)) {
                    columnMapping.put(column, entry.getValue());
                    break;
                }
            }

        }

        return columnMapping;
    }
    /** 发送物流短信 */
    @Override
    public ResultData send(LogisticsSmsModel model,Integer type) {
        log.info("发送物流短信:={}", JSON.toJSONString(model));
        Logistic logistic = getById(model.getLogisticId());
        if (type==0){
            if (model.getSendStatus()==1){
                logistic.setSendSmsStatus(SMS_STATUS_SENDING);
            }else if (model.getSendStatus()==2){
                logistic.setReceiveSmsStatus(SMS_STATUS_SENDING);
            }
            saveOrUpdate(logistic);
        }
        String sign="";
        if (logistic.getLogisticType()==SignEnum.getSign(1)){
            sign=SignEnum.getSign(1);
        }else{
            sign="随信送";
        }
        String content ="【" + sign + "】" + model.getContent();
        if (content.contains("$公司名称$")) {
            content = content.replace("$公司名称$", logistic.getLogisticType());
        }
        if (content.contains("$产品名称$")) {
            content = content.replace("$产品名称$", logistic.getProductName());
        }
        if (content.contains("$快递单号$")) {
            content = content.replace("$快递单号$", logistic.getLogisticNum());
        }
        if (content.contains("$快递公司$")) {
            content = content.replace("$快递公司$", logistic.getLogisticName());
        }
        if (content.contains("$操作人$")) {
            content = content.replace("$操作人$", model.getName());
        }
        if (content.contains("$站点$")) {
            content = content.replace("$站点$", model.getAddress());
        }
        try {
            // 构建短信发送参数
            SendSmsModel sendSmsModel = new SendSmsModel(
                    model.getOuterPhone(),
                    content
            );
            // 调用短信发送工具
            ResultData result = SmsPyUtil.sendCommonSms(sendSmsModel);
            log.info("短信发送结果:={}", JSON.toJSONString( result));
            //将发送短信记录保存到数据库
            SmsRecord smsRecord = new SmsRecord();
            smsRecord.setPRecordId((long) NUMBER_0);
            smsRecord.setCustomerId((long) NUMBER_0);
            Integer recordId = (Integer) result.getData();
            smsRecord.setRecordId(recordId.longValue());
            smsRecord.setCustomerPhone("");
            smsRecord.setOuterPhone(model.getOuterPhone());
            smsRecord.setOuterName(model.getOuterName());
            smsRecord.setSendStatus(model.getSendStatus());
            smsRecord.setSmsType(CHANNEL_TYPE_PLATFORM);
            smsRecord.setTemplateCategory(TEMPLATE_CATEGORY_LOGISTICS);
            smsRecord.setContent(content);
            smsRecord.setCreateTime(LocalDateTime.now());
            smsRecord.setSendTime(LocalDateTime.now());
            if (!result.isSuccess()) {
                smsRecord.setSmsStatus(SMS_STATUS_FALSE);
            }else {
                smsRecord.setSmsStatus(SMS_STATUS_SENDING);
            }
            smsRecord.insert();
            if (!result.isSuccess()) {
                return ResultData.failure("发送失败");
            }
            return ResultData.successData(result);
        } catch (Exception e) {
            log.error("短信发送异常: {}", e);
            return ResultData.failure("系统繁忙，请稍后重试");
        }
    }
    /**
     * 生成标准签名（MD5+Base64）
     */
    public String generateSign(String body) throws Exception {
        String strToSign = body + appSecret;
        // 修正Base64编码方式
        byte[] md5Bytes = DigestUtils.md5(strToSign.getBytes(StandardCharsets.UTF_8));
        return Base64Utils.encode(md5Bytes);
    }

    /**
     * 查询物流轨迹
     */
    @Override
    public String queryTrack(String billCode) throws Exception {
        // 1. 构造请求体（必须包含company_id）
        Map<String, String> requestMap = new HashMap<>();
        requestMap.put("billCode", billCode);
        requestMap.put("company_id", appKey);
        String requestBody = JSON.toJSONString(requestMap);

        // 2. 生成签名
        String sign = generateSign(requestBody);

        // 3. 构建完整请求
        CloseableHttpClient httpClient = HttpClients.createDefault();
        HttpPost httpPost = new HttpPost(url);
        httpPost.setHeader("Content-Type", "application/json");
        httpPost.setHeader("x-appKey", appKey);
        httpPost.setHeader("x-dataDigest", sign);
        httpPost.setEntity(new StringEntity(requestBody, StandardCharsets.UTF_8));

        // 4. 发送请求
        try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
            HttpEntity entity = response.getEntity();
            String rawJson = EntityUtils.toString(entity, StandardCharsets.UTF_8);

            JSONObject resultJson = JSON.parseObject(rawJson);
            if(resultJson.getBoolean("status")){
                JSONArray resultArray = resultJson.getJSONArray("result");

                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                sdf.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));

                for(int i = 0; i < resultArray.size(); i++) {
                    JSONObject item = resultArray.getJSONObject(i);
                    long timestamp = item.getLongValue("scanDate");
                    item.put("scanDateTime", sdf.format(new Date(timestamp)));
                }

                List<JSONObject> sortedList = resultArray.stream()
                        .map(o -> (JSONObject) o)
                        .sorted((a, b) -> Long.compare(b.getLong("scanDate"), a.getLong("scanDate")))
                        .collect(Collectors.toList());

                // 修复错误：直接使用排序后的List创建JSONArray
                resultJson.put("result", sortedList);
            }
            log.info("查询物流轨迹结果: {}", resultJson);
            return resultJson.toJSONString();
        } catch (ClientProtocolException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    /**获取物流状态*/
    @Override
    public ResultData getStatus() {
        List<Object> statusObjs = baseMapper.selectObjs(new LambdaQueryWrapper<Logistic>()
                .select(Logistic::getLogisticStatus)
                .groupBy(Logistic::getLogisticStatus)
                .isNotNull(Logistic::getLogisticStatus)
        );

        List<String> statusList = statusObjs.stream()
                .map(obj -> Optional.ofNullable(obj).map(Object::toString).orElse(""))
                .filter(StringUtils::isNotBlank)
                .collect(Collectors.toList());
        return ResultData.successData(statusList);
    }
    /**单个添加物流单号*/
    @Override
    public ResultData add(AddLogisticModel model) {
        Logistic logistic = new Logistic();
        BeanUtils.copyProperties(model, logistic);
        logistic.setLogisticStatus("");
        logistic.setSendSmsStatus(NUMBER_0);
        logistic.setReceiveSmsStatus(NUMBER_0);
        logistic.setCustomerId((long) NUMBER_0);
        logistic.setCreateTime(LocalDateTime.now());
        logistic.setUpdateTime(LocalDateTime.now());
        Boolean flag=saveOrUpdate(logistic);
        if (flag){
            return ResultData.successMsg("添加成功");
        }else {
            return ResultData.failure("添加失败");
        }
    }
}
